package org.mspring.platform.security.action.interceptor;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mspring.platform.security.SecurityUtils;
import org.mspring.platform.security.action.ActionSecurity;
import org.mspring.platform.security.action.rule.SecurityRule;
import org.mspring.platform.security.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 *
 * @author Gao Youbo
 * @since 2013年9月10日
 */
public class ActionSecurityInterceptor extends HandlerInterceptorAdapter {

    private static final Logger log = LoggerFactory.getLogger(ActionSecurityInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        ActionSecurity actionSecurity = handlerMethod.getMethodAnnotation(ActionSecurity.class);
        if (actionSecurity == null) {
            return super.preHandle(request, response, handler);
        }
        Class<? extends SecurityRule>[] ruleClass = actionSecurity.rules();
        boolean mustLogin = actionSecurity.mustLogin();
        if (!handleMustLogin(request, response, mustLogin)) {
            SecurityUtils.logout(request);
            try {
                response.sendRedirect(request.getContextPath() + "/login");
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
            return false;
        }
        if (handleRules(request, response, ruleClass)) {
            return true;
        }
        throw new AccessDeniedException("没有权限访问！");
    }

    protected boolean handleMustLogin(HttpServletRequest request, HttpServletResponse response, boolean mustLogin) {
        if (mustLogin == false) {
            return true;
        }
        User user = SecurityUtils.getCurrentUser(request);
        return user != null && !user.getDeleted();
    }

    @SuppressWarnings("unchecked")
    protected boolean handleRules(HttpServletRequest request, HttpServletResponse response, Class<? extends SecurityRule>... ruleClass) {
        if (ruleClass == null || ruleClass.length == 0) {
            return true;
        }
        boolean flag = true;
        for (Class<? extends SecurityRule> clazz : ruleClass) {
            SecurityRule rule = findAccessRule(clazz);
            if (rule == null) {
                continue;
            }
            if (!rule.shouldProceed(request, response)) {
                flag = false;
                try {
                    rule.handleError(request, response);
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
                break;
            }
        }
        return flag;
    }

    private SecurityRule findAccessRule(Class<? extends SecurityRule> ruleClass) {
        SecurityRule accessRule = ContextLoader.getCurrentWebApplicationContext().getBean(ruleClass);
        if (accessRule == null) {
            throw new NullPointerException(String.format("Could not find the rule %s. Have you registered it in the configuration file?", ruleClass.getName()));
        }
        return accessRule;
    }

}
